/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = zookeeper_request.c                                           */
/*  NOTE      = ZOOKEEPER协议解析                                             */
/*  DATE      = 2014/05/27 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "zookeeper_core.h"
#include "zookeeper_common.h"
#include "zookeeper_response.h"

#define ZOOKEEPER_PUB              APM_REPORT_KEY_PUB".zookeeper"
#define ZOOKEEPER_PUB_TYPE         ZOOKEEPER_PUB".type"
#define ZOOKEEPER_PUB_STATE        ZOOKEEPER_PUB".state"

int __zookeeper_report_pub(Conntrack *p_st_conn
                          , Frhash_header *p_st_hash_report
                          , Frlist_header *p_lst_hd)
{
    int i_ret = FR_SUCC;
    Frreport_data *p_st_report_data = NULL;
    Frreport_body_data *p_st_sess_body = NULL;
    char arr_key[128] = {0};
    snprintf(arr_key, sizeof(arr_key), "%s", ZOOKEEPER_PUB);
    char *p_key = arr_key;
    unsigned int ui_key_len = strlen(p_key);
    p_key += ui_key_len;
    ui_key_len = sizeof(arr_key) - ui_key_len;
    Frlist_node *p_st_node = NULL;
    Frvar_field *p_st_field = NULL;

    /* 创建report body */
    p_st_sess_body = frreport_body_new_l7(p_st_conn);
    if (p_st_sess_body == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 追加connection相关信息 */
    i_ret = frreport_body_l7_add_connInfo(p_st_sess_body, p_st_conn);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add title */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                     , APM_REPORT_KEY_TRANS_TITLE
                                     , "watch event");
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    ///* add type */
    //i_ret = frreport_body_l7_add_int(p_st_sess_body
    //                                 , ZOOKEEPER_PUB_TYPE
    //                                 , i_type);
    //if (i_ret != FR_SUCC)
    //{
    //    frreport_body_free(&p_st_sess_body);
    //    return APM_L7_ANALYZE_FAIL;
    //}

    ///* add state */
    //i_ret = frreport_body_l7_add_int(p_st_sess_body
    //                                 , ZOOKEEPER_PUB_STATE
    //                                 , i_state);
    //if (i_ret != FR_SUCC)
    //{
    //    frreport_body_free(&p_st_sess_body);
    //    return APM_L7_ANALYZE_FAIL;
    //}

    p_st_node = FRLIST_FIRST_NODE(p_lst_hd);
    while (p_st_node)
    {
        p_st_field = (Frvar_field *)FRLIST_GET_NODE_DATA(p_st_node);
        switch (p_st_field->em_data_type)
        {
            case FRSTRING:
                snprintf(p_key, ui_key_len, ".%s", p_st_field->p_field_name);
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_st_field->field_value.p_value ? p_st_field->field_value.p_value: "");
                break;

            default:
                i_ret = FR_FAIL;
            break;
        }
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    /* 创建report data header */
    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
    if (p_st_report_data == NULL)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add body into header */
    i_ret = frreport_data_add_body(p_st_report_data, p_st_sess_body);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        frreport_data_free(&p_st_report_data);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 上报request数据 */
    i_ret = frreport_data_hash(p_st_hash_report, p_st_report_data);
    if (i_ret != FR_SUCC)
    {
        frreport_data_free(&p_st_report_data);
        return APM_L7_ANALYZE_FAIL;
    }

    return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
}

/*******************************************************************************
*  FUNC     :  解析zookeeper请求
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*           :  p_st_hash_report(保存Frreport_data)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int zookeeper_parse_resp(Conntrack *p_st_conn
                        , L7session_zookeeper_private *p_st_private
                        , Frhash_header *p_st_hash_report)
{
    uint32_t u32_err_code = 0;
    int i_xid = 0;
    uint32_t u32_xid = 0;
    uint64_t u64_zxid = 0;
    long long ll_zxid = 0;
    //uint32_t u32_type = 0;
    //uint32_t u32_state = 0;
    int i_err_code = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    unsigned int ui_loop = 1;
    L7_resp_zookeeper *p_st_resp = NULL;
    L7_req_zookeeper *p_st_req = NULL;
    L7_fragment_zookeeper *p_st_fragment = p_st_private->p_st_fragment;
    Frbyte_Packet *p_st_data = p_st_fragment->p_st_data;
     Frhash_header *p_hash_header = p_st_private->p_hash_header;
    Frlist_node *p_st_node = NULL;
    Frlist_header st_head;
    memset(&st_head, 0x0, sizeof(Frlist_header));
    char arr_key[32] = {0};

    /* 长度不足 */
    if (bytebuff_remaining(p_st_data) < 4 + 8 + 4)
    {
        frdbg("response format incorrect!\n");
        zookeeper_init_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得xid */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_xid, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        zookeeper_init_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }
    i_xid = (int)u32_xid;

    /* 取得zxid */
    i_ret = bytebuff_get_long(p_st_data, 8, &u64_zxid, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        zookeeper_init_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }
    ll_zxid = (long long)u64_zxid;
    /* 查看是否是WATCHER EVENT */
    if (ll_zxid == ZOOKEEPER_WATCHER_EVENT_XID)
    {
        /* 没有request */

        while (bytebuff_remaining(p_st_data) > 4 + 4 + 4)
        {
            /* 跳过error code + type + state */
            bytebuff_skip(p_st_data, 4 + 4 + 4);
            ///* 解析type */
            //i_ret = bytebuff_get_int(p_st_data, 4, &u32_type, BYTE_BIG_ENDIAN);
            //if (i_ret != FR_SUCC)
            //{
            //    frdbg("zookeeper pub format incorrect!\n");
            //    zookeeper_init_curr_info(p_st_private);
            //    return APM_L7_ANALYZE_FAIL;
            //}
            ///* 解析state */
            //i_ret = bytebuff_get_int(p_st_data, 4, &u32_state, BYTE_BIG_ENDIAN);
            //if (i_ret != FR_SUCC)
            //{
            //    frdbg("zookeeper pub format incorrect!\n");
            //    zookeeper_init_curr_info(p_st_private);
            //    return APM_L7_ANALYZE_FAIL;
            //}
            snprintf(arr_key, sizeof(arr_key), "path.%d", ui_loop++);
            /* 取得path */
            i_ret = zookeeper_get_string(p_st_data, arr_key, &st_head);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("zookeeper pub format incorrect!\n");
                zookeeper_init_curr_info(p_st_private);
                return APM_L7_ANALYZE_FAIL;
            }

            /* 正确的格式是后面没有其他数据 */
            if (bytebuff_remaining(p_st_data) == 0)
            {
                i_ret = __zookeeper_report_pub(p_st_conn, p_st_hash_report, &st_head);
                frlist_remove_all(&st_head, frbindata_node_free);
                zookeeper_init_fragment(p_st_fragment);
                return i_ret;
            }
            /* 取得下一个 */
            /* 长度不足 */
            if (bytebuff_remaining(p_st_data) < 4 + 4 + 8)
            {
                frdbg("pub format incorrect!\n");
                zookeeper_init_curr_info(p_st_private);
                return APM_L7_ANALYZE_FAIL;
            }
            bytebuff_skip(p_st_data, 4 + 4 + 8);
        }

        frlist_remove_all(&st_head, frbindata_node_free);
        zookeeper_init_fragment(p_st_fragment);
        return APM_L7_ANALYZE_FAIL;
    }
    else
    {
        /* 根据xid取得对应的request */
        p_st_node = frhash2_getLong(p_hash_header, i_xid);
        p_st_req = (L7_req_zookeeper *) FRLIST_GET_NODE_DATA(p_st_node);
        /* 没有请求 */
        if (p_st_req == NULL)
        {
            frdbg("no request before!\n");
            zookeeper_init_curr_info(p_st_private);
            return APM_L7_ANALYZE_FAIL;
        }

        /* 取得err code */
        i_ret = bytebuff_get_int(p_st_data, 4, &u32_err_code, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            zookeeper_init_curr_info(p_st_private);
            return APM_L7_ANALYZE_FAIL;
        }
        i_err_code = (int)u32_err_code;

        /* 创建response */
        p_st_resp = (L7_resp_zookeeper *)frmalloc(sizeof(L7_resp_zookeeper));
        if (p_st_resp == NULL)
        {
            zookeeper_init_curr_info(p_st_private);
            return APM_L7_ANALYZE_FAIL;
        }
        memset(p_st_resp, 0x0, sizeof(L7_resp_zookeeper));
        p_st_resp->i_error_num = i_err_code;
        p_st_private->p_st_resp = p_st_resp;

        i_ret = zookeeper_report_data(p_st_conn, p_st_private, p_st_req, p_st_hash_report, FR_YES);
        zookeeper_init_curr_info(p_st_private);
        return i_ret;
    }
}
